<?php
	
	namespace Aspic\Controller;
	use Aspic as A;
	
	abstract class AbstractModule extends AbstractControllerBase {
		const MODULES_NS = 'Modules';
		const CLASS_LOADER_CLASS = 'Aspic\ClassLoader';

		const MODULES_CLASS_NAMES_SUFFIX = 'Module';
		const MODULES_CLASS_NAME = 'Module';
		
		const CONTROLLER_CLASS = 'Aspic\Controller\AbstractController';
		
		/**
		* @var string Namespace to the module
		*/
		private $_moduleNs;
		
		public function __construct($moduleNs, $specialParams) {
			parent::__construct(null, $specialParams);
			
			$this->_moduleNs = $moduleNs;
		}
		
		public static function loadModule($module, $controller, $action, array $params, $specialParams, $namespace) {
			$moduleClassPath = static::getModuleClassPath($module, $namespace);
			
			if(static::moduleExists($module, $namespace)) {
				
				$moduleNs = $namespace.'\\'.static::MODULES_NS.'\\'.static::getModuleDirName($module);
				$moduleInst = new $moduleClassPath($moduleNs, $specialParams);

				$viewRelativePath = $moduleInst->{static::INIT_METHOD_NAME}();
				
				if($moduleInst->isSuspended()) {
					if(!is_null($viewRelativePath)) {
						$this->loadViewRelativePath($viewRelativePath);
					}
				}
				else {
					call_user_func(
						array(
							static::CONTROLLER_CLASS, 
							'loadController')
						, 
						$controller, 
						$action, 
						$params, 
						$specialParams,
						$moduleInst
					);
				}
				
				$moduleInst->{static::END_METHOD_NAME}();
			}
			else {
				throw new ModuleNotFoundException($module, $moduleClassPath);
			}
		}
		
		public function getCurrentModuleNamespace() {
			return $this->_moduleNs;
		}
		
		public function getCurrentModulePath() {
			$modulePath = call_user_func(array(static::CLASS_LOADER_CLASS, 'getNamespacePath'), $this->getCurrentModuleNamespace());
			
			return $modulePath;
		}
		
		public function getCurrentModuleName() {
			return strtolower(substr(
				A\Util::getClassName($this),
				0,
				strpos(
					A\Util::getClassName($this), 
					static::MODULES_CLASS_NAMES_SUFFIX
				)
			));
		}
		
		public static function getModuleClassPath($moduleName, $namespace) {
			$classPath = A\UString::join('\\', $namespace, static::MODULES_NS, static::getModuleDirName($moduleName), static::getModuleClassName($moduleName));
			
			if(!class_exists($classPath)) {
				$classPath = A\UString::join('\\', $namespace, static::MODULES_NS, static::getModuleDirName($moduleName), static::MODULES_CLASS_NAME);
			}
			
			return $classPath;
		}
		
		/**
		* Get module class name from module name
		*/
		protected static function getModuleClassName($moduleName) {
			$className = ucfirst($moduleName).static::MODULES_CLASS_NAMES_SUFFIX;
			
			return $className;
//			return static::MODULES_CLASS_NAME;
		}
		
		/**
		* Return the directory name of a module from it's name
		*/
		protected static function getModuleDirName($moduleName) {
			$dirName = ucfirst($moduleName);
			
			return $dirName;
		}
		
		public static function moduleExists($moduleName, $namespace) {
			$classPath = static::getModuleClassPath($moduleName, $namespace);
			
			return class_exists($classPath);
		}
		
	}
	
?>